﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using xl.demo.models;
using xycn.common;
using xycn.IDbService;

namespace xl.demo.test
{
    class Program
    {
        static void Main(string[] args)
        {
            //Console.WriteLine("Hello World,test xmlconfig");

            //var conn = XmlConfigHelper.GetConfigToString("/Config/DBService/ConnString");

            //Console.WriteLine("conn" + conn);


            //var res = XmlConfigHelper.GetConfigToList("/Config/FrameworkConfig/HostUrls/Url");

            //Console.WriteLine(res.ToJsonString());

            //IDbService _dbhelper = new webapi.DbService.SugarService("server=47.115.18.214;port=4417; user id=rootdemo; password=rootdemo!2#4;database=demodb; pooling=false;CharSet=utf8;Allow Zero Datetime=True", "MySql");

            //var res = _dbhelper.GetList<Members, Members2, MemberView>((ma, mb) => new object[] {
            //                 JoinType.Left,ma.KID == mb.KID}, null, k => k.KID, OrderType.Asc);

            TestDynamicExpressionVisitor();

            Console.ReadKey();
        }

        /// <summary>
        /// 访问 表达式树 Expression<Func<int, int, int>> predicate1 = (m, n) => m * n + 2;
        /// (m, n) => m * n + 2;改成(m, n) => m * n - 2;
        /// </summary>
        public class OperatorExpressionVisitor : ExpressionVisitor
        {
            /// <summary>
            /// 修改表达式树的形式
            /// </summary>
            /// <param name="expression"></param>
            /// <returns></returns>
            public Expression Modify(Expression expression)
            {
                //base.Visit(expression);
                if (expression is BinaryExpression binary)
                {
                    if (binary.NodeType == ExpressionType.Add)
                    {
                        var left = base.Visit(binary.Left); ;
                        var right = base.Visit(binary.Right);
                        var result = Expression.Subtract(left, right);
                        return result;
                    }
                }

                List<LambdaExpression> lambda = null;
                VisitExpression2(expression, ref lambda);//解析取得表达式数中的表达式
                IEnumerable<List<Members>> enumerable = null;
                for (int i = 0; i < lambda.Count; i++)
                {
                    //把LambdaExpression转成Expression<Func<Student, bool>>类型
                    //通过方法Compile()转成委托方法
                    Func<Members, bool> func = (lambda[i] as Expression<Func<Members, bool>>).Compile();
                    //if (enumerable == null)
                    //    //enumerable = Program.StudentArrary.Where(func);//取得IEnumerable
                    //else
                    //    //enumerable = enumerable.Where(func);
                }
                //dynamic obj = enumerable.ToList();//（注意：这个方法的整个处理过程，你可以换成解析sql执行数据库查询，或者生成url然后请求获取数据。）
                //return (TResult)obj;

                return expression;
            }

            /// <summary>
            /// 表达式树的二元操作
            /// </summary>
            /// <param name="node"></param>
            /// <returns></returns>
            protected override Expression VisitBinary(BinaryExpression node)
            {
                return base.VisitBinary(node);
            }

            /// <summary>
            /// 表达式树的常量操作
            /// </summary>
            /// <param name="node"></param>
            /// <returns></returns>
            protected override Expression VisitConstant(ConstantExpression node)
            {
                return base.VisitConstant(node);
            }
        }

        /// <summary>
        /// 测试表达式树的访问过程
        /// </summary>
        public static void TestDynamicExpressionVisitor()
        {
            Expression<Func<int, int, int>> predicate = (m, n) => m * n + 2;
            //修改之前
            var func1 = predicate.Compile();
            var result1 = func1.Invoke(2, 3);
            Console.WriteLine($"参数2，3");
            Console.WriteLine($"修改---前");
            Console.WriteLine($"body：{predicate.Body}");
            Console.WriteLine($"结果：{result1}");


            OperatorExpressionVisitor visitor = new OperatorExpressionVisitor();
            var expression = visitor.Modify(predicate.Body);


            Expression<Func<int, int, int>> lam = Expression.Lambda<Func<int, int, int>>(expression, predicate.Parameters);
            var func = lam.Compile();
            var result = func.Invoke(2, 3);
            Console.WriteLine($"修改---后");
            Console.WriteLine($"body：{lam.Body}");
            Console.WriteLine($"结果：{result}");


            Expression<Func<Members, Members2, object[]>> joinExpression
                    = ((a, b) => new object[]{
                        JoinType.Left, a.KID == b.KID2
                    });

            OperatorExpressionVisitor visitor2 = new OperatorExpressionVisitor();
            var expression2 = visitor2.Modify(joinExpression.Body);


            Expression<Func<Members, Members2, object[]>> lam2
                = Expression.Lambda<Func<Members, Members2, object[]>>(expression2, joinExpression.Parameters);

            //var exjoin= Expression.Lambda


            Console.WriteLine($"body：{lam2.Body}");
        }


        public static void VisitExpression2(Expression expression, ref List<LambdaExpression> lambdaOut)
        {
            if (lambdaOut == null)
                lambdaOut = new List<LambdaExpression>();
            switch (expression.NodeType)
            {
                case ExpressionType.Call://执行方法
                    MethodCallExpression method = expression as MethodCallExpression;
                    Console.WriteLine("方法名:" + method.Method.Name);
                    for (int i = 0; i < method.Arguments.Count; i++)
                        VisitExpression2(method.Arguments[i], ref lambdaOut);
                    break;
                case ExpressionType.Lambda://lambda表达式
                    LambdaExpression lambda = expression as LambdaExpression;
                    lambdaOut.Add(lambda);
                    VisitExpression2(lambda.Body, ref lambdaOut);
                    break;
                case ExpressionType.Equal://相等比较
                case ExpressionType.AndAlso://and条件运算
                    BinaryExpression binary = expression as BinaryExpression;
                    Console.WriteLine("运算符:" + expression.NodeType.ToString());
                    VisitExpression2(binary.Left, ref lambdaOut);
                    VisitExpression2(binary.Right, ref lambdaOut);
                    break;
                case ExpressionType.Constant://常量值
                    ConstantExpression constant = expression as ConstantExpression;
                    Console.WriteLine("常量值:" + constant.Value.ToString());
                    break;
                case ExpressionType.MemberAccess:
                    MemberExpression Member = expression as MemberExpression;
                    Console.WriteLine("字段名称:{0}，类型:{1}", Member.Member.Name, Member.Type.ToString());
                    break;
                case ExpressionType.Quote:
                    UnaryExpression Unary = expression as UnaryExpression;
                    VisitExpression2(Unary.Operand, ref lambdaOut);
                    break;
                case ExpressionType.NewArrayInit:
                    NewArrayExpression array = expression as NewArrayExpression;

                    VisitExpression2(array, ref lambdaOut);
                    break;
                default:
                    Console.Write("UnKnow");
                    break;
            }
        }
    }
}
